package tmt.usercenter.web.controller;

import com.tmt.helper.ReflectHelper;
import com.tmt.spring.validation.RegFieldDescriptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.WebUtils;
import tmt.usercenter.web.Application;
import tmt.usercenter.web.controller.bean.WorkFlowManager;
import tmt.usercenter.web.controller.validtor.UserRegisterValidator;
import tmt.usercenter.web.domain.*;
import tmt.usercenter.web.domain.enums.NotifyType;
import tmt.usercenter.web.domain.security.UserDetailsImpl;
import tmt.usercenter.web.service.ClientSystemService;
import tmt.usercenter.web.service.TmtRoleService;
import tmt.usercenter.web.service.TmtUserService;
import tmt.usercenter.web.service.UserInfoConfigService;
import tmt.usercenter.web.utils.HttpServletRequestHelper;
import tmt.usercenter.web.vo.HttpResult;
import tmt.usercenter.web.vo.user.RegisterVo;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.*;
import java.util.stream.Collectors;

@RequestMapping("/register")
@Controller
public class RegisterController extends BaseController {
    public static final String NEW_USER = "_NEW_USER";
    public static final String DEFAULT_PASSWORD = "Az123456";

    @Autowired
    private TmtUserService userService;
    @Autowired
    private TmtRoleService roleService;
    @Autowired
    private UserInfoConfigService uiConfigService;
    @Autowired
    private ClientSystemService clientSystemService;
    @Autowired
    private UserRegisterValidator rgValidator;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @InitBinder("user")
    @Override
    protected void initBinder(WebDataBinder binder) {
        super.initBinder(binder);
        binder.addValidators(rgValidator);
    }

    @RequestMapping(method = RequestMethod.GET)
    public String register(HttpServletRequest request) {
        getIntroducerCode(request);
        return "redirect:/register/flow" + (StringUtils.isEmpty(request.getQueryString()) ? "" : "?" + request.getQueryString());
    }

    @RequestMapping(value = "/flow", method = RequestMethod.GET)
    public String register(HttpServletRequest request, HttpServletResponse response, Model model) {

        request.getSession().removeAttribute(NEW_USER);

        String clientId = getClientId(request);
        UserInfoConfig config = uiConfigService.findByOriginSystemClientId(clientId, true);

        String param = "?" + request.getQueryString();

        //确定注册流程。
        List<String> stepList = new ArrayList<>();
        stepList.add("redirect:/register/flow" + param);

        if (config.getRequiredInfo().size() > 0) {
            stepList.add("redirect:/register/baseInfo" + param);
        }

        if (config.isCheckPhone()) {
            if (config.isCheckEmail()) {
                if (config.isFirstCheckPhone()) {
                    stepList.add("redirect:/mobile/flow" + param);
                    stepList.add("redirect:/email/flow" + param);
                } else {
                    stepList.add("redirect:/email/flow" + param);
                    stepList.add("redirect:/mobile/flow" + param);
                }
            } else {
                stepList.add("redirect:/mobile/flow" + param);
            }
        } else if (config.isCheckEmail()) {
            stepList.add("redirect:/email/flow" + param);
        }

        //注册完毕后跳转到页面
        stepList.add("redirect:/register/success" + param);

        WorkFlowManager.clear(request);
        WorkFlowManager.insertFlowNodes(request, stepList);

        //进入第一个流程
        return WorkFlowManager.next(request, "error/404");
    }

    /**
     * 填写基本信息
     *
     * @param request
     * @param response
     * @param model
     * @return
     */
    @RequestMapping(value = "/baseInfo", method = RequestMethod.GET)
    public String baseInfo(HttpServletRequest request, HttpServletResponse response, Model model) {
        String url = WorkFlowManager.assure(request, "redirect:/register");
        if (!StringUtils.isEmpty(url))
            return url;

        String clientId = getClientId(request);
        WebUtils.setSessionAttribute(request, "registerClientId", clientId);
        return initialRegisterModelAndView(clientId, null, null, model);
    }

    @RequestMapping(value = "/baseInfo", method = RequestMethod.POST)
    public String baseInfo(HttpServletRequest request,
                           HttpServletResponse response,
                           Model model,
                           @Valid @ModelAttribute("user") RegisterVo registerVo,
                           BindingResult result) {
        //确保当前
        String url = WorkFlowManager.assure(request, "redirect:/register");
        if (!StringUtils.isEmpty(url))
            return url;

        String clientId = getClientId(request);
        UserInfoConfig config = uiConfigService.findByOriginSystemClientId(clientId, false);
        if (config == null) {
            return "error/500";
        }

        //如果存在配置的必填字段错误，则返回填写页面。
        if (result.hasErrors()
                && result.getAllErrors().stream().anyMatch(x -> config.getRequiredInfo().contains(((FieldError) x).getField()))) {
            return initialRegisterModelAndView(clientId, registerVo, config, model);
        }

        //创建新用户。
        String host = request.getRequestURL().toString().split(request.getRequestURI())[0];
        host = host + request.getContextPath();
        String defaultAvatar = TmtFileUrlFieldConverter.getDefaultFileUrl(host, TmtUser.class, "avatar");
        TmtUser user = registerVo.convertToUser(defaultAvatar, UUID.randomUUID().toString(), DEFAULT_PASSWORD);

        //设置会员的邀请码字
        Long introducerCode = getIntroducerCode(request);
        user.setIntroducerCode(introducerCode);

        ClientSystem originSystem = clientSystemService.findByClientId(clientId);

        //设置用户角色
        List<TmtUserRole> roleList = new ArrayList<>();
        user.setUserRoles(roleList);

        ClientSystem system = clientSystemService.findByClientId(Application.SYSTEM_ID);
        TmtRole role = roleService.findDefaultRoleByOriginSystemId(system.getId());
        if (role != null)
            roleList.add(new TmtUserRole(user, role));

        if (!Objects.equals(originSystem.getId(), system.getId())) {
            TmtRole role1 = roleService.findDefaultRoleByOriginSystemId(originSystem.getId());
            if (role1 != null) {
                roleList.add(new TmtUserRole(user, role1));
            }
        }

        user.setOriginSystem(originSystem);
        request.getSession().setAttribute(NEW_USER, user);

        //进入下一个流程
        return WorkFlowManager.next(request, "error/404");
    }

    @RequestMapping(value = "/success")
    public String registerSuccess(HttpServletRequest request, Model model) {


        String result = "redirect:/register";

        TmtUser user = null;
        String errorMsg = null;
        try {
            String url = WorkFlowManager.assure(request, result);
            if (!StringUtils.isEmpty(url))
                return url;

            Object obj = request.getSession().getAttribute(NEW_USER);
            if (obj != null) {
                user = (TmtUser) obj;
                if (user.getId() == null) {
                    user.setPassword(passwordEncoder.encode(user.getPassword()));
                    try {
                        user = userService.loadEntity(TmtUser.class, "registerNewUser", new Object[]{user}, "1");

                        //创建线程通知客户端：新用户注册成功。
                        TmtUser finalUser = user;
                        Thread thread = new Thread(() -> {
                            UserDetailsImpl details = userService.getUserDetailsImpl(finalUser.getId(), finalUser.getOriginSystem().getClientId());
                            clientSystemService.sendNotifyToClient(finalUser.getOriginSystem().getClientId(), NotifyType.NEW_USER, details);
                        });
                        thread.start();

                    } catch (Exception ex) {
                        user = null;
                        errorMsg = "创建用户对象失败";
                    }
                }
                WorkFlowManager.clear(request);

                request.getSession().setAttribute("last_new_user_id", user.getId());
            } else {
                obj = request.getSession().getAttribute("last_new_user_id");
                if (obj == null) {
                    throw new Exception("last_new_user_id参数不存在");
                }
                Long userId = (Long) obj;
                user = userService.findById(userId);
                request.getSession().removeAttribute("last_new_user_id");
            }
        } catch (Exception ex) {
            user = null;
            errorMsg = "创建新用户异常：" + ex.getMessage();
        } finally {
            request.getSession().removeAttribute(NEW_USER);
            request.getSession().removeAttribute(INTRODUCER_CODE);
        }

        String clientId = (String) WebUtils.getSessionAttribute(request, "registerClientId");
        ClientSystem originSystem = clientSystemService.findByClientId(clientId);

        String url = "";
        if (originSystem.getRegisteredRedirectUri().size() >= 1) {
            url = originSystem.getRegisteredRedirectUri().get(0);
        }

        if (HttpServletRequestHelper.isMobileDevice(request)
                && !StringUtils.isEmpty(originSystem.getAppDownloadUrl())) {
            return "redirect:" + originSystem.getAppDownloadUrl();
        }

        model.addAttribute("newUser", user);
        model.addAttribute("errMsg", errorMsg);
        model.addAttribute("url", url);
        model.addAttribute("appUrl", !StringUtils.isEmpty(originSystem.getAppDownloadUrl())
                ? originSystem.getAppDownloadUrl() : "");
        result = "user/reg-success";

        return result;
    }

    /**
     * 动态获取字段输入提示
     *
     * @param hintField
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/hint/{hintField}")
    public HttpResult getHint(HttpServletRequest request, @PathVariable("hintField") String hintField) {
        try {
            RegisterVo registerVo = new RegisterVo();

            Map<String, String[]> param = request.getParameterMap();
            if (param != null && param.size() > 0) {
                param.forEach((key, value) -> ReflectHelper.setFieldValue(registerVo, key, value[0]));
            }

            List<RegFieldDescriptor> regFieldDescriptors = rgValidator.getRegFieldDescriptors(registerVo, Arrays.asList(hintField));
            return HttpResult.success(regFieldDescriptors.get(0).getFieldHint());
        } catch (Exception ex) {
        }
        return HttpResult.failure();
    }

    private String initialRegisterModelAndView(String clientId, RegisterVo registerVo, UserInfoConfig config, Model model) {
        if (registerVo == null) {
            registerVo = new RegisterVo();
            registerVo.setClientId(clientId);
        }

        if (config == null)
            config = uiConfigService.findByOriginSystemClientId(clientId, false);

        List<RegFieldDescriptor> regFieldDescriptors = rgValidator.getRegFieldDescriptors(registerVo, config.getRequiredInfo());
        List<RegFieldDescriptor> baseFields = regFieldDescriptors.stream()
                .filter(c -> Arrays.asList("username", "password", "verify", "clientId").contains(c.getFieldName()))
                .collect(Collectors.toList());

        regFieldDescriptors.removeAll(baseFields);

        ClientSystem cs = clientSystemService.findByClientId(clientId);

        model.addAttribute("client", cs);
        model.addAttribute("user", registerVo);
        model.addAttribute("fieldDescriptors", regFieldDescriptors);
        model.addAttribute("baseFields", baseFields);
        model.addAttribute("appUrl", cs.getAppDownloadUrl());
        return "user/reg-baseInfo";
    }

}
